/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package operator.server;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import share.AliveCheckThread;
import share.Server;
import share.SocketCommunicator;

/**
 *
 * @author mire
 */
public class OperatorServer extends Server implements Runnable {
//TODO: telnet zatvori

    final static private String confName = ".os.conf";
    final static private String backupUsersName = ".users";
    final static private String backupServersName = ".servers";
    final static private String backupClientsName = ".clients";
    final static private String backupNumbersName = ".numbers";
    private String operatorName;
    private String[] operatorPrefix;
    private String centralAddress;
    private int globalCentralPort;
    private String operatorAddress;
    private int operatorPort;
    private int clientPort;
    private int aliveTimeout;
    private int waitForAnswerTime;
    private Date lastTimeSynchronized;
    private ExecutorService fixedThreadPool;
    private ScheduledExecutorService aliveCheckThread = null;
    private ExecutorService centralListener = null;
    private ExecutorService operatorListener = null;
    private ExecutorService clientListener = null;
    private ConcurrentHashMap<Integer, OperatorUser> users;
    private ConcurrentHashMap<Integer, OperatorUser> centralDownUsers;
    private ConcurrentHashMap<Integer, Server> servers;
    private ConcurrentSkipListSet<String> clients;
    private ConcurrentSkipListSet<String> numbers;
    private OperatorLog transferLog;
    private boolean restored;
    private boolean centralServerOnline;
    SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss dd.MM.yyyy");

    public OperatorServer(String operatorName, String[] operatorPrefix, String centralAddress, int globalCentralPort, String operatorAddress, int operatorPort, int clientPort, int aliveTimeout, int waitForAnswerTime, int threadNo, int centralPort) {
        super(threadNo, centralPort);
        this.operatorName = operatorName;
        this.operatorPrefix = operatorPrefix;
        this.centralAddress = centralAddress;
        this.globalCentralPort = globalCentralPort;
        this.operatorAddress = operatorAddress;
        this.operatorPort = operatorPort;
        this.clientPort = clientPort;
        this.aliveTimeout = aliveTimeout;
        this.waitForAnswerTime = waitForAnswerTime;
        users = new ConcurrentHashMap<Integer, OperatorUser>();
        centralDownUsers = new ConcurrentHashMap<Integer, OperatorUser>();
        servers = new ConcurrentHashMap<Integer, Server>(2);
        clients = new ConcurrentSkipListSet<String>();
        numbers = new ConcurrentSkipListSet<String>();
        transferLog = new OperatorLog();
        backupConfiguration();
        restored = false;
        centralServerOnline = false;
    }

    public OperatorServer() {
        super(0);
        operatorAddress = null;
        users = new ConcurrentHashMap<Integer, OperatorUser>();
        centralDownUsers = new ConcurrentHashMap<Integer, OperatorUser>();
        servers = new ConcurrentHashMap<Integer, Server>(2);
        clients = new ConcurrentSkipListSet<String>();
        numbers = new ConcurrentSkipListSet<String>();
        transferLog = new OperatorLog();
        restoreAll();
        restored = true;
        centralServerOnline = false;
    }

    public int getAliveTimeout() {
        return aliveTimeout;
    }

    public String getCentralAddress() {
        return centralAddress;
    }

    public int getGlobalCentralPort() {
        return globalCentralPort;
    }

    public String[] getOperatorPrefix() {
        return operatorPrefix;
    }

    public int getClientPort() {
        return clientPort;
    }

    public ConcurrentSkipListSet<String> getClients() {
        return clients;
    }

    public Date getLastTimeSynchronized() {
        return lastTimeSynchronized;
    }

    public String getOperatorAdress() {
        return operatorAddress;
    }

    public String getOperatorName() {
        return operatorName;
    }

    public int getOperatorPort() {
        return operatorPort;
    }

    public ConcurrentHashMap<Integer, Server> getServers() {
        return servers;
    }

    public ConcurrentSkipListSet<String> getNumbers() {
        return numbers;
    }

    public ConcurrentHashMap<Integer, OperatorUser> getUsers() {
        return users;
    }

    public ConcurrentHashMap<Integer, OperatorUser> getCentralDownUsers() {
        return centralDownUsers;
    }

    public int getWaitForAnswerTime() {
        return waitForAnswerTime;
    }

    public OperatorLog getTransferLog() {
        return transferLog;
    }


    public synchronized boolean isCentralServerOnline() {
        return centralServerOnline;
    }

    public synchronized void checkCentralServerOnline() {
        if (!isCentralServerOnline()) {
            return;
        }

        SocketCommunicator socComm = null;

        try {
            socComm = new SocketCommunicator(new Socket(centralAddress, globalCentralPort), 1);
            socComm.open();

            socComm.writeString("ALIVE");
            if (!socComm.readString().equals("YES")) {
                setCentralServerOnline(false);
            }
        } catch (UnknownHostException ex) {
            setCentralServerOnline(false);
        } catch (IOException ex) {
            setCentralServerOnline(false);
        } finally {
            if (socComm != null) {
                try {
                    socComm.close();
                } catch (IOException ex) {
                }
            }
        }
    }

    public synchronized void setCentralServerOnline(boolean stateCentralServer) {
        this.centralServerOnline = stateCentralServer;
    }

    public synchronized void setLastTimeSynchronized(Date lastTimeSynchronized) {
        this.lastTimeSynchronized = lastTimeSynchronized;
    }

    public void setAliveTimeout(int aliveTimeout) {
        stopCheckAliveThread();
        this.aliveTimeout = aliveTimeout;
        startCheckAliveThread();
        backupConfiguration();
    }

    public void setCentralAddress(String centralAddress) {
        stopCentralListener();
        this.centralAddress = centralAddress;
        startCentralListener();
        backupConfiguration();
    }

    public void setCentralPort(int centralPort) {
        stopCentralListener();
        this.centralPort = centralPort;
        startCentralListener();
        backupConfiguration();
    }

    public void setClientPort(int clientPort) {
        stopClientListener();
        this.clientPort = clientPort;
        startClientListener();
        backupConfiguration();
    }

    public void setOperatorPort(int operatorPort) {
        stopOperatorListener();
        this.operatorPort = operatorPort;
        startOperatorListener();
        backupConfiguration();
    }

    public void setWaitForAnswerTime(int waitForAnswerTime) {
        this.waitForAnswerTime = waitForAnswerTime;
        backupConfiguration();
    }

    @Override
    public void run() {
        String time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Starting Operator Server!");

        if (operatorAddress != null) {
            registerSelfatOther(operatorAddress);
        } else if (restored) { //ako se ponovo dize, treba da se sinhronizuje
            registerSelfatOthers();
        }

        backupAll();

        registerSelfatCentral();


        fixedThreadPool = Executors.newFixedThreadPool(threadNo);

        startCentralListener();
        startOperatorListener();
        startClientListener();

        time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Operator Server up!");

        try {
            Thread.sleep(new Date().getTime());
        } catch (InterruptedException ex) {
            Logger.getLogger(OperatorServer.class.getName()).log(Level.SEVERE, null, ex);
            backupAll();
        }
    }

    private void startCentralListener() {
        String time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Starting Central Server Listener...");
        centralListener = Executors.newSingleThreadExecutor();
        centralListener.execute(new OperatorCentralListener(this, fixedThreadPool));
    }

    private void stopCentralListener() {
        centralListener.shutdownNow();
    }

    private void startOperatorListener() {
        String time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Starting Operator Server Listener...");
        operatorListener = Executors.newSingleThreadExecutor();
        operatorListener.execute(new OperatorOperatorListener(this, fixedThreadPool));
        startCheckAliveThread();
    }

    private void stopOperatorListener() {
        stopCheckAliveThread();
        operatorListener.shutdownNow();
    }

    private void startClientListener() {
        String time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Starting Operator Client Listener...");
        clientListener = Executors.newSingleThreadExecutor();
        clientListener.execute(new OperatorClientListener(this, fixedThreadPool));
    }

    private void stopClientListener() {
        clientListener.shutdownNow();
    }

    private void startCheckAliveThread() {
        aliveCheckThread = Executors.newSingleThreadScheduledExecutor();
        aliveCheckThread.scheduleAtFixedRate(
                new AliveCheckThread(servers, operatorPort, backupServersName),
                aliveTimeout, aliveTimeout, TimeUnit.SECONDS);
    }

    private void stopCheckAliveThread() {
        aliveCheckThread.shutdown();
    }

    public ConcurrentHashMap<Integer, OperatorUser> parseUsers(String manyUsers, String oldOperator) {
        ConcurrentHashMap<Integer, OperatorUser> multipleUsers = new ConcurrentHashMap<Integer, OperatorUser>();
        String workingString = manyUsers.replace('{', ' ').replace('}', ' ').replaceAll(" ", "");
        String[] splited = workingString.split(",");
        for (int i = 0; i < splited.length; i++) {
            String[] userSplited = splited[i].split("=");
            OperatorUser user = new OperatorUser(Integer.parseInt(userSplited[0]), userSplited[1], oldOperator, operatorName);
            multipleUsers.put(user.getId(), user);
        }
        return multipleUsers;
    }

    public ArrayList<Integer> parseUserIDs(String manyUsers) {
        ArrayList<Integer> multipleIDs = new ArrayList<Integer>();
        String workingString = manyUsers.replace('{', ' ').replace('}', ' ').replaceAll(" ", "");
        String[] splited = workingString.split(",");
        for (int i = 0; i < splited.length; i++) {
            String[] userSplited = splited[i].split("=");
            multipleIDs.add(Integer.parseInt(userSplited[0]));
        }
        return multipleIDs;
    }

    public ArrayList<String> parseUserNumbers(String manyUsers) {
        ArrayList<String> multipleNumbers = new ArrayList<String>();
        String workingString = manyUsers.replace('{', ' ').replace('}', ' ').replaceAll(" ", "");
        String[] splited = workingString.split(",");
        for (int i = 0; i < splited.length; i++) {
            String[] userSplited = splited[i].split("=");
            multipleNumbers.add(userSplited[1]);
        }
        return multipleNumbers;
    }

    public synchronized static boolean existsConfugration() {
        File f = new File(confName);
        return f.exists();
    }

    public synchronized final void backupAll() {
        backupConfiguration();
        backupUsers();
        backupServers();
        backupClients();
        backupNumbers();
    }

    public final synchronized boolean restoreAll() {
        restoreConfiguration();
        restoreUsers();
        restoreServers();
        restoreClients();
        restoreNumbers();
        return true;
    }

    public final synchronized void backupConfiguration() {
        File f = new File(confName);
        if (f.exists()) {
            f.delete();
        }

        FileWriter fw = null;
        PrintWriter outp = null;
        try {
            fw = new FileWriter(f);
            outp = new PrintWriter(fw, true);
            String line = "";

            outp.println(operatorName);
            for (int i = 0; i < operatorPrefix.length; i++) {
                if (i != 0) {
                    line += " ";
                }
                line += operatorPrefix[i];
            }
            outp.println(line);
            outp.println(centralAddress);
            outp.println(globalCentralPort);
            outp.println(centralPort);
            outp.println(operatorPort);
            outp.println(clientPort);
            outp.println(aliveTimeout);
            outp.println(waitForAnswerTime);
            outp.println(threadNo);
            if (lastTimeSynchronized != null) {
                outp.println(lastTimeSynchronized.getTime());
            } else {
                outp.println("\t");
            }

        } catch (IOException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (outp != null) {
                    outp.close();
                }
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public synchronized boolean restoreConfiguration() {
        File f = new File(confName);
        if (!f.exists()) {
            return false;
        }

        FileReader fr = null;
        LineNumberReader inr = null;
        try {
            fr = new FileReader(f);
            inr = new LineNumberReader(fr);
            String line = null;

            operatorName = inr.readLine();
            line = inr.readLine();
            operatorPrefix = line.split(" ");
            centralAddress = inr.readLine();
            globalCentralPort = Integer.parseInt(inr.readLine());
            centralPort = Integer.parseInt(inr.readLine());
            operatorPort = Integer.parseInt(inr.readLine());
            clientPort = Integer.parseInt(inr.readLine());
            aliveTimeout = Integer.parseInt(inr.readLine());
            waitForAnswerTime = Integer.parseInt(inr.readLine());
            threadNo = Integer.parseInt(inr.readLine());
            line = inr.readLine();
            if (line.equals("\t")) {
                lastTimeSynchronized = null;
            } else {
                lastTimeSynchronized = new Date(Long.parseLong(line));
            }
        } catch (NumberFormatException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (inr != null) {
                    inr.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return true;
    }

    public synchronized void backupUsers() {
        if (users.isEmpty()) {
            return;
        }

        File f = new File(backupUsersName);
        if (f.exists()) {
            f.delete();
        }

        FileWriter fw = null;
        PrintWriter outp = null;
        try {
            fw = new FileWriter(f);
            outp = new PrintWriter(fw, true);

            for (Iterator<OperatorUser> it = users.values().iterator(); it.hasNext();) {
                OperatorUser user = it.next();

                String line = "";
                line += user.getId();
                line += "\t";
                line += user.getNumber();
                line += "\t";
                line += user.getCreationTime().getTime();
                line += "\t";
                line += user.getCurrentOperator();
                line += "\t";
                line += user.getOldOperator();

                outp.println(line);
            }
        } catch (IOException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (outp != null) {
                    outp.close();
                }
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    public synchronized boolean restoreUsers() {
        File f = new File(backupUsersName);
        if (!f.exists()) {
            return false;
        }

        FileReader fr = null;
        LineNumberReader inr = null;
        try {
            fr = new FileReader(f);
            inr = new LineNumberReader(fr);

            String line = null;
            while ((line = inr.readLine()) != null) {
                String[] splited = line.split("\t");
                int id = Integer.parseInt(splited[0]);
                Date time = new Date(Long.parseLong(splited[2]));
                OperatorUser user = new OperatorUser(id, splited[1], time, splited[3], splited[4]);
                users.put(id, user);
            }

        } catch (IOException ex) {
            //kraj fajla
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (inr != null) {
                    inr.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (users.isEmpty()) {
            return false;
        }

        return true;
    }

    public synchronized void backupServers() {
        File f = new File(backupServersName);
        if (f.exists()) {
            f.delete();
        }
        FileWriter fw = null;
        PrintWriter outp = null;
        try {
            fw = new FileWriter(f);
            outp = new PrintWriter(fw, true);

            for (Iterator<Server> it = servers.values().iterator(); it.hasNext();) {
                Server server = it.next();

                outp.println(server.getAddress() + " " + server.getThreadNo() + " " + server.getCentralPort());
            }

        } catch (IOException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (outp != null) {
                    outp.close();
                }
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public synchronized boolean restoreServers() {
        File f = new File(backupServersName);
        if (!f.exists()) {
            return false;
        }

        FileReader fr = null;
        LineNumberReader inr = null;
        String line = null;
        try {
            fr = new FileReader(f);
            inr = new LineNumberReader(fr);

            while ((line = inr.readLine()) != null) {
                String[] splited = line.split(" ");
                Server newServer = new Server(splited[0], Integer.parseInt(splited[1]), Integer.parseInt(splited[2]));
                servers.put(newServer.hashCode(), newServer);
            }

        } catch (IOException ex) {
            //kraj fajla
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (inr != null) {
                    inr.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        return true;
    }

    public synchronized void backupClients() {
        if (clients.isEmpty()) {
            return;
        }

        File f = new File(backupClientsName);
        if (f.exists()) {
            f.delete();
        }
        FileWriter fw = null;
        PrintWriter outp = null;
        try {
            fw = new FileWriter(f);
            outp = new PrintWriter(fw, true);

            for (Iterator<String> it = clients.iterator(); it.hasNext();) {
                outp.println(it.next());
            }

        } catch (IOException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (outp != null) {
                    outp.close();
                }
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public synchronized boolean restoreClients() {
        File f = new File(backupClientsName);
        if (!f.exists()) {
            return false;
        }

        FileReader fr = null;
        LineNumberReader inr = null;
        String line = null;
        try {
            fr = new FileReader(f);
            inr = new LineNumberReader(fr);

            while ((line = inr.readLine()) != null) {
                clients.add(line);
            }

        } catch (IOException ex) {
            //kraj fajla
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (inr != null) {
                    inr.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        return true;

    }

    public synchronized void backupNumbers() {
        if (numbers.isEmpty()) {
            return;
        }

        File f = new File(backupNumbersName);
        if (f.exists()) {
            f.delete();
        }
        FileWriter fw = null;
        PrintWriter outp = null;
        try {
            fw = new FileWriter(f);
            outp = new PrintWriter(fw, true);

            for (Iterator<String> it = numbers.iterator(); it.hasNext();) {
                outp.println(it.next());
            }

        } catch (IOException ex) {
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (outp != null) {
                    outp.close();
                }
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public synchronized boolean restoreNumbers() {
        File f = new File(backupNumbersName);
        if (!f.exists()) {
            return false;
        }

        FileReader fr = null;
        LineNumberReader inr = null;
        String line = null;
        try {
            fr = new FileReader(f);
            inr = new LineNumberReader(fr);

            while ((line = inr.readLine()) != null) {
                numbers.add(line);
            }

        } catch (IOException ex) {
            //kraj fajla
            Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (inr != null) {
                    inr.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        return true;

    }

    private void registerSelfatOthers() {
        String time = null;

        time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Registering self at others operator servers...");
        Iterator<Server> it = servers.values().iterator();
        while (it.hasNext()) {
            String address = it.next().getAddress();
            if (address.equals(this.getAddress())) {
                continue;
            }
            registerSelfatOther(address);
        }
    }

    private boolean registerSelfatOther(String address) {
        String time = null;

        SocketCommunicator socComm = null;
        boolean registered = true;

        try {
            socComm = new SocketCommunicator(new Socket(address, operatorPort));
            socComm.open();

            socComm.writeString("NEW_SERVER");
            socComm.readString(); //REQUEST_ACCEPTED

            socComm.writeObject(new Server(threadNo, centralPort));

            Date synchonizedTime = (Date) socComm.readObject();
            if (lastTimeSynchronized != null && lastTimeSynchronized.equals(synchonizedTime)) {
                socComm.writeString("SYNCHRONIZED_ALREADY");
                socComm.close();
            } else {
                lastTimeSynchronized = synchonizedTime;
                socComm.writeString("NOT_SYNCHRONIZED");

                users = (ConcurrentHashMap<Integer, OperatorUser>) socComm.readObject();
                centralDownUsers = (ConcurrentHashMap<Integer, OperatorUser>) socComm.readObject();
                numbers = (ConcurrentSkipListSet<String>) socComm.readObject();
                servers = (ConcurrentHashMap<Integer, Server>) socComm.readObject();
                clients = (ConcurrentSkipListSet<String>) socComm.readObject();
                String fileLog = socComm.readString();

                transferLog = new OperatorLog(fileLog);

                socComm.writeString("DATA_RECIEVED");
                socComm.close();
            }

        } catch (ClassNotFoundException ex) {
            Logger.getLogger(OperatorServer.class.getName()).log(Level.SEVERE, null, ex);
            registered = false;
        } catch (UnknownHostException ex) {
            Logger.getLogger(OperatorServer.class.getName()).log(Level.SEVERE, null, ex);
            registered = false;
        } catch (IOException ex) {
            Logger.getLogger(OperatorServer.class.getName()).log(Level.SEVERE, null, ex);
            registered = false;
        } finally {
            try {
                if (socComm != null) {
                    socComm.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(OperatorServer.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + address + " " + (registered ? "registered" : "failed"));

        return registered;
    }

    private void registerSelfatCentral() {
        String time = null;
        SocketCommunicator socComm = null;
        int tries = 0;

        time = dateFormat.format((new Date()).getTime()) + " ";
        System.out.println(time + "Registering at central server...");
        while (true) {
            try {
                socComm = new SocketCommunicator(new Socket(centralAddress, globalCentralPort), waitForAnswerTime);
                socComm.open();

                socComm.writeString("NEW_SERVER");
                socComm.writeString(operatorName);

                String responce = socComm.readString();

                socComm.writeObject(new Server(threadNo, centralPort));
                socComm.readString();
                socComm.close();
                centralServerOnline = true;
                time = dateFormat.format((new Date()).getTime()) + " ";
                System.out.println(time + "Regitered!");
                break;

            } catch (UnknownHostException ex) {
                centralServerOnline = false;
            } catch (IOException ex) {
                centralServerOnline = false;
            } finally {
                if (socComm != null) {
                    try {
                        socComm.close();
                    } catch (IOException ex) {
                    }
                }
            }
            if (!isCentralServerOnline() && (tries < 2)) {
                synchronized (this) {
                    tries++;
                    time = dateFormat.format((new Date()).getTime()) + " ";
                    System.out.println(time + "ERROR Central server offline! Try " + tries + ".");
                    try {
                        this.wait(waitForAnswerTime * 1000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(OperatorServer.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            } else {
                time = dateFormat.format((new Date()).getTime()) + " ";
                System.out.println(time + "ERROR Central server offline! Try " + ++tries + ". Quiting...");
                break;
            }
        }
    }

    public boolean isNumberFree(String number) {
        return numbers.contains(number);
    }

    public String getFreeNumber() {
        Random generatorRandom = new Random((new Date()).getTime());
        String number = "";
        while (true) {
            number = "";

            int indexPrefix = generatorRandom.nextInt(operatorPrefix.length);
            number += operatorPrefix[indexPrefix];

            for (int j = 0; j < 6; j++) {
                number += generatorRandom.nextInt(10);
            }

            if (!numbers.contains(number)) {
                break;
            }

        }

        numbers.add(number);

        return number;
    }

    public boolean numberOk(String userNumber) {
        boolean check = false;
        String workNumber = userNumber.replaceAll("\\D", "");

        for (int i = 0; i < operatorPrefix.length; i++) {
            String regEx = "^" + operatorPrefix[i] + "\\d{6}";

            Pattern pattern = Pattern.compile(regEx);
            Matcher matcher = pattern.matcher(workNumber);

            check = matcher.find();
        }

        return check;
    }
}
